#ifndef FS_LIGHT_POOL_H
#define FS_LIGHT_POOL_H

#include "lightContainers.h"
#include "Camera.h"
#include <vector>
using namespace std;

#define MAX_SPOT_LIGHTS 4096
#define MAX_POINT_LIGHTS 4096

class ds_LightPool {
public:
	static ds_LightPool* Instance();
	static void Destroy(bool atexit = false);

	// Adding lights
	void addPointLight(vec3 location, vec3 color, float fadeFar = 12.0f, float cutoffFar = 15.0f);
	void addDirectionalLight(vec3 direction, vec3 color);
	void addSpotLight(vec3 location, vec3 direction, vec3 color, float halfAngle = 30.0f,
		float fadeFar = 12.0f, float cutoffFar = 15.0f);

	// Forward Renderer - in batches
	int numDirectionalLightBatches();
	int numPointLightBatches();
	int numSpotLightBatches();
	ds_directional_light_batch directionalLightBatch(unsigned int batchNumber);
	ds_point_light_batch pointLightBatch(unsigned int batchNumber);
	ds_spot_light_batch spotLightBatch(unsigned int batchNumber);

	// Regular deferred renderer - one light at a time
	ds_point_light* pointLight(int lightNumber);
	ds_directional_light directionalLight(int lightNumber);
	ds_spot_light* spotLight(int lightNumber);
	int numPointLights();
	int numDirectionalLights();
	int numSpotLights();

	// Tile-base deferred renderer
	// Point and directional lights should probably just be handled by regular deferred shading
	ds_point_light_device pointLightCudaPointers(mat4 *persp, int width, int height, Camera *cam, bool viewChanged = true);
	void setInversePerspective(mat4 persp);

private:
	ds_LightPool();
	ds_LightPool(ds_LightPool const&) { };
	ds_LightPool& operator=(ds_LightPool const&);
	~ds_LightPool();

	static ds_LightPool *m_instance;

	vector<ds_point_light> pointLights;
	vector<ds_directional_light> directionalLights;
	vector<ds_spot_light> spotLights;

	float *pointLightFloats;
	int *pointLightScissorRects;
	float *d_spotLightFloats, *d_pointLightFloats;
	int *d_pointLightScissorRects;
	unsigned int numSpotLightsUInt, numPointLightsUInt;
	bool plCudaNeedsUpdate;

	void updatePointScissorRects(mat4 *persp, int width, int height, Camera *cam);
	void updatePointLightsCuda();
};

#endif // #ifndef FS_LIGHT_POOL_H